 /* 
  Copyright Software Engineering Research laboratory <serl@cs.wichita.edu>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public
 License as published by the Free Software Foundation; either
 version 2 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Library General Public License for more details.

 You should have received a copy of the GNU Library General Public
 License along with this program; if not, write to the Free
 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 */

package wichita.edu.xfinder;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/*
 * @author: Sara Bahrami <mxbahramizanjani@wichita.edu>
 * 
 * This class contatins SAX XML Parser for parsing the review log and creates 3 different dictionary
 * mPathReviewDict- key: File name with absolute path, value: an object from class of ReviewTuple
 * mPathReviewDict- this dictionary is using for calculating XFactor value for each file in class XFinder
 * 
 * mBugReviewrInfo-key:BugId , value: Reviewers name
 * mBugReviewrInfo- this dictionary is using for different purposes such as calculating accuracy of approach
 * 
 * mBugStatusOwner-key:BugId, value: status and owner
 * 
 */
public class Dictionary extends DefaultHandler{
	//dictionary which for each file includes all of the related reviewers's name and review date and bug id
	HashMap<String, ArrayList<ReviewTuple>> mPathReviewDict;
	//dictionary which for each bug id includes all of the reviewers's names related to that bug id
	HashMap<String, ArrayList<String>> mBugReviewrInfo;
	//Dictionary which for each bugd id includes the status, instead of using just one string for each Bugid an Arraylist of string
	//used because it's possible for one bug id there are multiple reviews and each review has different status 
	HashMap<String,ArrayList<StatusOwner>> mBugStatusOwner;
	ArrayList<ReviewTuple> reviews;
	ArrayList<String> reviewerNames;
	ArrayList<StatusOwner> statuesownerlist;
	//keep the list of files in each patch set for each review
	ArrayList<String> files;
	String bugid;
	String status;
	String owner;
    String xmlLogFilepath;
    String tmpValue;
    ReviewTuple reviewNode;
    StatusOwner statusOwnerNode;
    
    public Dictionary(String xmlLogFilepath)
    {
        this.xmlLogFilepath = xmlLogFilepath;
        this.mPathReviewDict =  new HashMap<String, ArrayList<ReviewTuple>>();
        this.mBugReviewrInfo=new HashMap<String, ArrayList<String>>();
        this.mBugStatusOwner=new HashMap<String,ArrayList<StatusOwner>>();
        parseDocument();
    }

    private void parseDocument()
    {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try
        {
            SAXParser parser = factory.newSAXParser();
            parser.parse(xmlLogFilepath,this);
        }
        catch (ParserConfigurationException e)
        {
            e.printStackTrace();
        }
        catch (SAXException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

    }
    
   public void printmPathReviewDict()
    {
	   for (Entry<String, ArrayList<ReviewTuple>> entry : mPathReviewDict.entrySet())
		  for(int i=0;i<entry.getValue().size();i++ )
			{
				System.out.print(entry.getKey() + " ");
				System.out.print(entry.getValue().get(i).mBugID + " ");
				System.out.print(entry.getValue().get(i).mReviewer + " ");
				System.out.println(entry.getValue().get(i).mDate);
			}       
    }
    
   public void printmBugReviewrInfo()
   {
	   for (Entry<String, ArrayList<String>> entry : mBugReviewrInfo.entrySet())
		  for(int i=0;i<entry.getValue().size();i++ )
			{
				System.out.print(entry.getKey() + " ");
				System.out.println(entry.getValue().get(i));
			}       
   }
   
   //Related function for SAX Parser
    public void startElement(String s, String s1, String element, Attributes attributes) throws SAXException
    {
        if (element.equalsIgnoreCase("BugId"))
        {
        	files=new ArrayList<String>();
        	bugid=attributes.getValue("Id");
        	status=attributes.getValue("status");
        }
        
        if(element.equalsIgnoreCase("Owner"))
        {
        	owner=attributes.getValue("name");
        	AddElementtomBugStatusOwner(bugid,status,owner);
        }
        if (element.equalsIgnoreCase("Info"))
        {
        	reviewNode = new ReviewTuple();
        	reviewNode.setmBugID(Integer.parseInt(bugid));
        	try {
				reviewNode.setmDate(formatDate(attributes.getValue("date")));
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        	reviewNode.setmReviewer(attributes.getValue("name"));
        	AddElementtomBugReviewrInfo(bugid,attributes.getValue("name"));
        }
        
        if (element.equalsIgnoreCase("File"))
        {
        	files.add(attributes.getValue("path"));
        }
        
    }
    //Related function for SAX Parser
    public void endElement(String s, String s1, String element) throws SAXException 
    {
        if(element.equals("BugId"))
        {
        	files.clear();
        }
        
        //if element is Info add the reviewr names and dates to dictionary "mPathReviewDict"
        if(element.equalsIgnoreCase("Info"))
        {     	
        	
        	for(int k=0;k<files.size();k++)
        	{
        		String fileName = files.get(k);
        		if (!mPathReviewDict.containsKey(fileName))
            		{
        				reviews=new ArrayList<ReviewTuple>();	
            			
            		}
        			else if (mPathReviewDict.containsKey(fileName))      					
        					
        			{	
        				reviews= mPathReviewDict.get(fileName);
        				
        			}
        		reviews.add(reviewNode);
        		mPathReviewDict.put(fileName,reviews);
        	}
   
        }

    }
   // Related function for SAX Parser 
    public void characters(char[] ac, int i, int j) throws SAXException
    {
        tmpValue = new String(ac,i,j);
    }
    
    //Convert String to Date
    public Date formatDate(String date) throws ParseException
    {
    	String pattern="yyyy-mm-dd";
 		SimpleDateFormat format=new SimpleDateFormat(pattern);
 		Date daterightformat=format.parse(date);
    	return daterightformat;
    }
    //GET
    public HashMap<String, ArrayList<ReviewTuple>> getmPathReviewDict()
    {
    	return mPathReviewDict;
    }
    
    public HashMap<String, ArrayList<String>> getmBugReviewrInfo()
    {
    	return mBugReviewrInfo;
    }
    
    public HashMap<String, ArrayList<StatusOwner>> getmBugStatusOwner()
    {
    	return mBugStatusOwner;
    }
    
    //Adds bugid and reviewers for each bugid to Doctionary for using later in Utility Package
    public void AddElementtomBugReviewrInfo(String bugid,String name)
    {
    	 
    	if (!mBugReviewrInfo.containsKey(bugid))
		{
    		reviewerNames=new ArrayList<String>();	
			
		}
		else if (mBugReviewrInfo.containsKey(bugid))      					
				
		{	
			reviewerNames= mBugReviewrInfo.get(bugid);
			
		}
		reviewerNames.add(name);
		mBugReviewrInfo.put(bugid,reviewerNames);
    	
    }
    
  //Adds bugid and status for each bugid to Doctionary mBugStatus for using later in Utility Package
    public void AddElementtomBugStatusOwner(String bugid,String status,String owner)
    {
    	
    	
    	if (!mBugStatusOwner.containsKey(bugid))
		{
			statuesownerlist=new ArrayList<StatusOwner>();	
			
		}
		else if (mBugStatusOwner.containsKey(bugid))      					
				
		{	
			statuesownerlist= mBugStatusOwner.get(bugid);
			
		}
    	
    	statusOwnerNode=new StatusOwner(status,owner);
    	//System.out.println(bugid);
    	statuesownerlist.add(statusOwnerNode);
    	mBugStatusOwner.put(bugid,statuesownerlist);
    	
    }
}